﻿

using HBase;
using HBase.db;
using System;
using System.Collections.Generic;
using System.Linq;

namespace hCommand {
   
    public enum TaskDir {
        前进 = 1,
        原位 = 2,
        后退 = 3
    }
    [Serializable]
    public abstract class BaseTask:RAM, ICloneable, CacheData {

        public short driveId = 0;
        public bool canWorkType = true;
        public BaseTask(short c) {
            driveId = c;
        }
        public BaseTask() {
            className = GetType().Name;

        }

        public List<long> relyTask = new List<long>();

        public bool canWork() {
            if (!canWorkType) {
                return false;
            }
            foreach (var refore in relyTask) {

                bool can = canWork(id,refore,relyTask);
                if (!can) {
                    return false;
                }
            }

            return true;
        }


        public virtual bool canWork(long meId,long beforeId,List<long> relyTask) {
            BaseTask me = PathFacade.getTaskById(meId);
            BaseTask b = PathFacade.getTaskById(beforeId);

            if (b == null) {
                return true;
            }
            if (me.src == b.des) {
                bool res = b.status >= (int)CoreTaskParamStatus.执行结束;
                if (!res) {
                    LoggerCommon.consoleOnly(0,"依赖{0}{1}{2}",me.className,me.taskNo,b.taskNo);
                }
                return res;
            }

            return true;

        }
        public String className {
            get; set;
        }
        public bool same(BaseTask o) {
            return o.taskNo == taskNo && o.src == src;
        }

        public void initBase(CoreTask complete,CoreTaskParam p,TaskDto dto,List<TaskDto> keyList) {
            taskNo = p.taskNo;
            code = complete.boxCode;
            completeId = complete.id;
            completeParamId = p.id;

            src = dto.src;
            des = dto.des;
            status = (int)CoreTaskParamStatus.待执行;
            waveNo = complete.waveNo;
            if (p.type == (int)TaskParamType.组内移位 || p.type == (int)TaskParamType.进组重定) {
                if (dto == keyList[keyList.Count - 1]) {
                    canWorkType = false;
                }
            }
            init(complete,p,dto,keyList);
        }
        public abstract void init(CoreTask complete,CoreTaskParam p,TaskDto dto,List<TaskDto> keyList);

        public virtual bool isFinsh(int stn) {
            return des == stn;
        }

        public virtual int getDes() {
            return des;
        }
        public virtual int getSrc() {
            return src;
        }
        public int taskNo {
            get; set;
        }
        public string code {
            get; set;
        }
        public int priority {
            get; set;
        }
        public short status {
            get; set;
        }
        public long completeId {
            get; set;
        }
        public long completeParamId {
            get; set;
        }

        public string extra {
            get; set;
        }
        public int src {
            get; set;
        }
        public int des {
            get; set;
        }

        public String waveNo {
            get; set;
        }

      

        public abstract List<String> getLableData();
        public static object obj = new object();

        static public List<BaseTask> getTaskByCompleteId(Type type,long id) {
            lock (obj) {
                List<BaseTask> baselist = MyCache.getList<BaseTask>(type);
                IEnumerable<BaseTask> res = baselist.Where((a) => {
                    return a.completeId == id;
                });
                return res.ToList();
            }
        }


        public static T getValue<T>(long key) where T : BaseTask {
            String name = typeof(T).Name;
            return MyCache.getValue<T>(name,key);
        }

        static public List<T> getTaskListByTaskNo<T>(int taskNO) where T : BaseTask {
            Type type = typeof(T);
            lock (obj) {
                return query<T>((a) => {
                    return a.taskNo == taskNO;
                });
            }
        }
        static public N3 getNextTaskByTaskNo<N1, N2, N3>(int taskNo,int stn) where N1 : BaseTask where N2 : BaseTask where N3 : BaseTask {
            lock (obj) {
                N1 n1 = queryUnique<N1>((a) => {
                    return a.taskNo == taskNo && a.des == stn;
                },taskNo + " at " + stn);

                N2 n2 = queryUnique<N2>((a) => {
                    return n1.completeId == a.completeId && n1.des == a.src;
                },taskNo + " at " + n1.des);

                N3 n3 = queryUnique<N3>((a) => {
                    return n2.completeId == a.completeId && n2.des == a.src;
                },taskNo + " at " + n2.des);
                return n3;
            }
        }
        static public N2 getStart2ContinueTaskByStn<N1, N2>(int stn) where N1 : BaseTask where N2 : BaseTask {//rgv put to carrier 
            lock (obj) {

                List<N2> res2 = getStart2ContinueTasksByStn<N1,N2>(stn);
                int count = res2.Count();
                if (count > 1) {
                    throw new Exception(stn + "待执行任务过多");
                } else if (count == 1) {
                    return res2[0];
                } else {
                    return null;
                }
            }
        }
        static public List<N2> getStart2ContinueTasksByStn<N1, N2>(int stn) where N1 : BaseTask where N2 : BaseTask {//rgv put to carrier 
            lock (obj) {
                List<long> completeIds = query<N1>((a) => {
                    return a.des == stn && a.status < (int)CoreTaskParamStatus.执行结束 && a.status >= (int)CoreTaskParamStatus.待执行;
                }).Select(a => { return a.completeId; }).ToList();

                List<N2> res2 = query<N2>((a) => {
                    return a.src == stn && a.status == (int)CoreTaskParamStatus.待执行 && !completeIds.Contains(a.completeId);
                });
                return res2;
            }
        }
        static public List<N2> getStart2ContinueTaskByStnAll<N1, N2>(int stn) where N1 : BaseTask where N2 : BaseTask {//rgv put to carrier 
            lock (obj) {
                List<long> completeIds = query<N1>((a) => {
                    return a.des == stn && a.status < (int)CoreTaskParamStatus.执行结束 && a.status >= (int)CoreTaskParamStatus.待执行;
                }).Select(a => { return a.completeId; }).ToList();

                List<N2> res2 = query<N2>((a) => {
                    return a.src == stn && a.status == (int)CoreTaskParamStatus.待执行 && !completeIds.Contains(a.completeId);
                });
                int count = res2.Count();
                return res2;
            }
        }
        static public List<BaseTask> getStart2ContinueTaskByStn(int stn) {//rgv put to carrier 
            lock (obj) {
                List<Type> list = PathFacade.getAllTaskType();
                List<long> completeIds = new List<long>();
                foreach (var type in list) {
                    var completeIds1 = MyCache.getList<BaseTask>(type).Where((a) => {
                        return a.des == stn && a.status < (int)CoreTaskParamStatus.执行结束 && a.status >= (int)CoreTaskParamStatus.待执行;
                    }).Select(a => { return a.completeId; });
                    completeIds.AddRange(completeIds1);
                }
                List<BaseTask> res = new List<BaseTask>();
                foreach (var type in list) {
                    var tasks = MyCache.getList<BaseTask>(type).Where((a) => {
                        return a.src == stn && a.status == (int)CoreTaskParamStatus.待执行 && !completeIds.Contains(a.completeId);
                    });
                    res.AddRange(tasks);
                }
                return res;
            }
        }
        static public List<BaseTask> getTaskByCoreTaskId(long id) {//rgv put to carrier 
            lock (obj) {
                List<Type> list = PathFacade.getAllTaskType();
                List<BaseTask> res = new List<BaseTask>();
                foreach (var type in list) {
                    var bts = MyCache.getList<BaseTask>(type).Where((a) => {
                        return a.completeId == id;
                    });
                    res.AddRange(bts);
                }
                return res;
            }
        }

        static public N getNextTaskByTaskNo<M, N>(int stn,int taskNo) where M : BaseTask where N : BaseTask {
            lock (obj) {
                M n1 = queryUnique<M>((a) => {
                    return a.taskNo == taskNo && a.des == stn;
                },"任务" + taskNo);
                if (n1 == null) {
                    N n3 = queryUnique<N>((a) => {
                        return a.taskNo == taskNo && a.src == stn;
                    },taskNo + "站台异常");
                    return n3;
                }
                N n2 = queryUnique<N>((a) => {
                    return a.completeId == n1.completeId && a.src == stn;
                },n1.completeId + "" + n1.des);
                return n2;
            }
        }

        static public T getByCode<T>(string code,int startPath) where T : BaseTask {
            lock (obj) {
                return queryUnique<T>((a) => {
                    T carrier = (T)a;
                    return (String.IsNullOrWhiteSpace(code) || code == carrier.code) && (startPath == 0 || startPath == carrier.src);
                },code + "从" + startPath);
            }
        }

        static public List<T2> getTasksByStn<T1, T2>(int stn) where T1 : BaseTask where T2 : BaseTask {
            lock (obj) {
                List<T2> res = new List<T2>();
                List<T2> t2list = query<T2>((a) => {
                    return a.src == stn && a.status == (int)CoreTaskParamStatus.待执行;
                }).ToList();

                foreach (T2 t2 in t2list) {
                    T1 t1 = queryUnique<T1>((a) => {
                        T1 t = (T1)a;
                        return (t.completeId == t2.completeId && t.des == t2.src);
                    },t2.taskNo + "获取多个前置任务");
                    if (t1 == null || t1.status == (int)CoreTaskParamStatus.执行结束) {
                        res.Add(t2);
                    }

                }
                return res;
            }
        }

        static public List<T> getAllTask<T>(string code,int startPath) where T : BaseTask {
            lock (obj) {
                return query<T>((a) => {

                    return (String.IsNullOrWhiteSpace(code) || code == a.code) && (startPath == 0 || startPath == a.src);
                });
            }
        }
        static public T getTaskByTaskNo<T>(int taskNo) where T : BaseTask {
            lock (obj) {
                return queryUnique<T>((a) => {
                    return a.taskNo == taskNo;
                },"任务" + taskNo);
            }
        }
        static public T getTaskByTaskNo<T>(short driveId,int taskNo) where T : BaseTask {// 木道rgv  
            lock (obj) {
                return queryUnique<T>((a) => {
                    return a.taskNo == taskNo && driveId == a.driveId;
                },"任务" + taskNo);
            }
        }

        private static T queryUnique<T>(Func<BaseTask,bool> func,String errorInfo) where T : BaseTask {
            IEnumerable<T> res = query<T>(a => func(a));
            if (res.Count() > 1) {
                throw new Exception(errorInfo + "任务数量过多");
            } else {
                T r = res.FirstOrDefault();
                if (r == null) {
                    return null;
                } else {
                    return (T)r;
                }
            }
        }

        private static List<T> query<T>(Func<BaseTask,bool> func) where T : BaseTask {
            Type type = typeof(T);
            List<T> baselist = MyCache.getList<T>(type);
            List<T> res = baselist.Where(a => func(a)).ToList();
            return res;
        }
    }
}
